package com.xique.park.mq.consumer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.xique.common.core.constant.Constants;
import com.xique.common.core.utils.AliossUtil;
import com.xique.park.bean.domain.*;
import com.xique.park.bean.dto.ParkOutDto;
import com.xique.park.bean.dto.PayOrderDto;
import com.xique.park.mq.bean.ParkingOrderOnMsg;
import com.xique.park.service.biz.service.IParkWxMessageSendBizService;
import com.xique.park.service.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author shd
 * @create 2022/7/29 10:41
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PaymentMqConsumer {

    private final IParkThirdPartyPushService parkThirdPartyPushService;

    private final MsgIdempotentService msgIdempotentService;

    private final IParkMqFailMsgService parkMqFailMsgService;

    private final IParkLaneService parkLaneService;

    private final IParkInService parkInService;

    private final IParkOutService parkOutService;

    private final IPayOrderService payOrderService;

    private final AliossUtil aliossUtil;

    private final IParkWxMessageSendBizService parkWxMessageSendBizService;

    public void receive(ParkingOrderOnMsg parkingOrderOnMsg) {
        try {
            Long msgId = parkingOrderOnMsg.getMsgId();
            if (null != msgId) {
                // 插入数据库，防止重复消费
                if (saveParkMqMsg(parkingOrderOnMsg)) {
                    ParkingOrderOn parkingOrderOn = parkingOrderOnMsg.getParkingOrderOn();
                    if (null != parkingOrderOn) {
                        Long parkId = parkingOrderOn.getParkId();
                        ParkThirdPartyPush parkThirdPartyPush = getParkThirdPartyPush(parkId);
                        // 判断车场是否需要推订单记录
                        if (parkThirdPartyPush != null && parkThirdPartyPush.getOrderPush() == Constants.TRUE) {
                            // 组织信息
                            Map<String, Object> paramMap = paramMap(parkingOrderOn);

                            // 推送
                            push(parkThirdPartyPush, paramMap, parkId, parkingOrderOn);
                        }

                        // 进场消息推送到对应用户的公众号
                        parkWxMessageSendBizService.delayPaymentProcess(parkingOrderOn);
                    } else {
                        log.warn("[支付结果通知]-支付结果消息中的订单信息为空，{}", parkingOrderOnMsg);
                    }
                } else {
                    log.warn("[支付结果通知]-消息已经被消费过了，{}", parkingOrderOnMsg);
                }
            } else {
                log.warn("[支付结果通知]-支付结果消息ID为空，{}", parkingOrderOnMsg);
            }
        } catch (Exception e) {
            // 将处理失败的消息存入数据库
            saveParkMqFailMsg(parkingOrderOnMsg);

            log.error("[支付结果通知]-消息处理异常，异常信息：{}，{}", e.getMessage(), parkingOrderOnMsg);
            e.printStackTrace();
        }
    }

    private boolean saveParkMqMsg(ParkingOrderOnMsg parkingOrderOnMsg) {
        String msgMd5 = MD5.create().digestHex(JSON.toJSONString(parkingOrderOnMsg));
        MsgIdempotent parkMqMsg = new MsgIdempotent();
        parkMqMsg.setMsgMd5(msgMd5);
        parkMqMsg.setCreateTime(new Date());
        return msgIdempotentService.save(parkMqMsg);
    }

    private ParkThirdPartyPush getParkThirdPartyPush(Long parkId) {
        return parkThirdPartyPushService.selectOneByParkId(parkId);
    }

    private Map<String, Object> paramMap(ParkingOrderOn parkingOrderOn) {
        Map<String, Object> paramMap = new HashMap<>(18);
        Long parkId = parkingOrderOn.getParkId();
        String parkingSerial = parkingOrderOn.getParkingSerial();

        // 订单信息
        paramMap.put("parkId", parkingOrderOn.getParkId());
        paramMap.put("carPlate", parkingOrderOn.getPlate());
        paramMap.put("parkingSerial", parkingSerial);
        paramMap.put("totalFee", parkingOrderOn.getTotalFee());
        paramMap.put("paidFee", parkingOrderOn.getPaidFee());
        paramMap.put("couponFee", parkingOrderOn.getCouponFee());
        paramMap.put("payFee", parkingOrderOn.getPayFee());

        ParkOutDto parkOutDto = getParkOut(parkId, parkingSerial);
        if (null != parkOutDto) {
            // 出场信息
            paramMap.put("outPic", StrUtil.isNotBlank(parkOutDto.getOutPic()) ? aliossUtil.getJzyGetObjectUrl(parkOutDto.getOutPic()) : "");
            paramMap.put("outTime", parkOutDto.getOutTime());
            paramMap.put("outLaneName", parkOutDto.getLaneName());
            paramMap.put("outStatus", parkOutDto.getStatus());
            paramMap.put("mngType", parkOutDto.getMngType());
            paramMap.put("mngTypeName", parkOutDto.getMngName());

            Long inId = parkOutDto.getInId();
            ParkIn parkIn = getParkIn(inId);
            if (null != parkIn) {
                // 入场信息
                paramMap.put("inTime", parkIn.getInTime());
                paramMap.put("inPic", StrUtil.isNotBlank(parkIn.getInPic()) ? aliossUtil.getJzyGetObjectUrl(parkIn.getInPic()).toString() : "");
                paramMap.put("inLaneName", getLaneName(parkIn.getInLaneId()));
                paramMap.put("inStatus", parkIn.getStatus());
            }
        }

        PayOrderDto payOrderDto = getPayOrder(parkId, parkingSerial);
        if (null != payOrderDto) {
            // 支付信息
            paramMap.put("payTime", payOrderDto.getPayTime());
        }

        return paramMap;
    }

    private PayOrderDto getPayOrder(Long parkId, String parkingSerial) {
        List<PayOrderDto> payOrderDtoList = payOrderService.selectPayOrderByParkingSerial(parkId, parkingSerial);
        if (CollUtil.isNotEmpty(payOrderDtoList)) {
            return payOrderDtoList.get(0);
        }
        return null;
    }

    private ParkOutDto getParkOut(Long parkId, String parkingSerial) {
        List<ParkOutDto> parkOutDtoList = parkOutService.selectParkOutByParkingSerial(parkId, parkingSerial);
        if (CollUtil.isNotEmpty(parkOutDtoList)) {
            return parkOutDtoList.get(0);
        }
        return null;
    }

    private ParkIn getParkIn(Long inId) {
        return parkInService.getById(inId);
    }

    private String getLaneName(Long laneId) {
        ParkLane parkLane = parkLaneService.selectParkLaneById(laneId);
        if (null != parkLane) {
            return parkLane.getName();
        }
        return "";
    }

    private void push(ParkThirdPartyPush parkThirdPartyPush, Map<String, Object> paramMap, Long parkId, ParkingOrderOn parkingOrderOn) {
        String orderPushUrl = parkThirdPartyPush.getOrderPushUrl();
        if (StrUtil.isNotBlank(orderPushUrl)) {
            String json = JSON.toJSONString(paramMap);
            String httpResponse = HttpUtil.post(orderPushUrl, json);
            log.info("[支付结果通知]-支付结果推送地址：{}，推送信息：{}，推送结果：{}", orderPushUrl, paramMap, httpResponse);
        } else {
            log.warn("[支付结果通知]-车场未配置订单记录推送地址，车场：{}，{}", parkId, parkingOrderOn);
        }
    }

    private void saveParkMqFailMsg(ParkingOrderOnMsg parkingOrderOnMsg) {
        ParkMqFailMsg parkMqFailMsg = new ParkMqFailMsg();
        parkMqFailMsg.setMsgId(parkingOrderOnMsg.getMsgId());
        parkMqFailMsg.setMsg(JSON.toJSONString(parkingOrderOnMsg));
        parkMqFailMsg.setCreateTime(new Date());
        parkMqFailMsgService.save(parkMqFailMsg);
    }

}
